/**
 * @author haina.z@163.com
 * @brief header file.
 * @version V1.0
 */

#ifndef __STORE_FLASH_H
#define __STORE_FLASH_H

/** Includes -----------------------------------------------------------------*/
#include "public_defs.h"
#include "math/math.h"
#include "store_data.h"

/** C++ { --------------------------------------------------------------------*/
#ifdef __cplusplus
extern "C" {
#endif

/** Macros (#define) ---------------------------------------------------------*/

// Result definition
#define STORE_FLASH_DATA_FOUND                              (bmBit0)
#define STORE_FLASH_DATA_ABNORMAL                           (bmBit1)
#define STORE_FLASH_CRC_ERROR                               (bmBit2)
#define STORE_FLASH_CRC_OK                                  (bmBit3)
#define STORE_FLASH_RESTORE_SUCCESS                         (bmBit4)

/** Type definitions ---------------------------------------------------------*/
// 存储信息
typedef struct
{
    uint32_t u32StartAddress;
    uint32_t u32EndAddress;

    uint16_t u16BlockSize;
    uint8_t u8BlockNumber;

    uint8_t u8AlignSize; // 对齐字节数
    uint8_t u8MessageType; // 信息类型
} StoreFlashInfo_t;

// 存储数据
typedef struct
{
    const StoreData_t * pList;
    uint8_t u8Num; // data number

    uint8_t * pBuffer;
    uint8_t u8BufSize; // buffer size
} StoreFlashData_t;

// 存储控制
typedef struct
{
    uint32_t u32ReadAddress;
    uint32_t u32WriteAddress;
    uint8_t u8ReadLength;
    uint8_t u8Result;
} StoreFlashCtrl_t;

// 存储对象
typedef struct
{
    const StoreFlashInfo_t * pInfo;
    const StoreFlashData_t * pData;
    StoreFlashCtrl_t oCtrl;
} StoreFlashObject_t;

typedef struct
{
    uint8_t u8Type;
    uint8_t u8CRC;
    uint8_t u8Length;
    /*lint -e43*/
    uint8_t MsgBody[0];
} StoreMessage_t;

/** External variable declarations (extern) ----------------------------------*/

/** Function declarations (prototypes) ---------------------------------------*/
/**
 * @brief 获取按StoreMessage_t存储的信息
 */
void StoreFlash_GetInfo(StoreFlashObject_t * pObject);
/**
 * @brief 如果已找到数据，则读取数据，并判断CRC是否正确
 */
void StoreFlash_ReadData(StoreFlashObject_t * pObject);
/**
 * @brief 如果存储的数据正确，则恢复数据
 */
void StoreFlash_RestoreData(StoreFlashObject_t * pObject);
/**
 * @brief 存储的数据是否改变
 */
bool StoreFlash_DataIsChanged(StoreFlashObject_t * pObject);
/**
 * @brief 存储数据，如果已经到块的最后，不够存储，则先擦除
 */
void StoreFlash_SaveData(StoreFlashObject_t * pObject);

/** Macros (#define) ---------------------------------------------------------*/

// Search result
#define mStoreFlash_SetDataFound(pObj)                      {(pObj)->oCtrl.u8Result |= STORE_FLASH_DATA_FOUND;}
#define mStoreFlash_ClrDataFound(pObj)                      {(pObj)->oCtrl.u8Result &= ~STORE_FLASH_DATA_FOUND;}
#define mStoreFlash_DataIsFound(pObj)                       ((pObj)->oCtrl.u8Result & STORE_FLASH_DATA_FOUND)

#define mStoreFlash_SetDataAbnormal(pObj)                   {(pObj)->oCtrl.u8Result |= STORE_FLASH_DATA_ABNORMAL;}
#define mStoreFlash_ClrDataAbnormal(pObj)                   {(pObj)->oCtrl.u8Result &= ~STORE_FLASH_DATA_ABNORMAL;}
#define mStoreFlash_DataIsAbnormal(pObj)                    ((pObj)->oCtrl.u8Result & STORE_FLASH_DATA_ABNORMAL)

// Restore result
#define mStoreFlash_SetCrcError(pObj)                       {(pObj)->oCtrl.u8Result |= STORE_FLASH_CRC_ERROR;}
#define mStoreFlash_ClrCrcError(pObj)                       {(pObj)->oCtrl.u8Result &= ~STORE_FLASH_CRC_ERROR;}
#define mStoreFlash_CrcIsError(pObj)                        ((pObj)->oCtrl.u8Result & STORE_FLASH_CRC_ERROR)

#define mStoreFlash_SetCrcOK(pObj)                          {(pObj)->oCtrl.u8Result |= STORE_FLASH_CRC_OK;}
#define mStoreFlash_ClrCrcOK(pObj)                          {(pObj)->oCtrl.u8Result &= ~STORE_FLASH_CRC_OK;}
#define mStoreFlash_CrcIsOK(pObj)                           ((pObj)->oCtrl.u8Result & STORE_FLASH_CRC_OK)

#define mStoreFlash_SetRestoreSuccess(pObj)                 {(pObj)->oCtrl.u8Result |= STORE_FLASH_RESTORE_SUCCESS;}
#define mStoreFlash_ClrRestoreSuccess(pObj)                 {(pObj)->oCtrl.u8Result &= ~STORE_FLASH_RESTORE_SUCCESS;}
#define mStoreFlash_RestoreIsSuccess(pObj)                  ((pObj)->oCtrl.u8Result & STORE_FLASH_RESTORE_SUCCESS)

// Message head size
#define STORE_MSG_HEAD_SIZE                                 sizeof(StoreMessage_t)

// Align size
#define mStoreFlash_Align(number, align_size)               (((number) % (align_size)) ? ((number) - ((number) % (align_size)) + (align_size)) : (number))

/**
 * 创建Flash相关的变量
 * name: 对象名字
 * start_address: 起始地址
 * end_address: 结束地址
 * block_size: 块大小
 * block_number: 块个数
 * align_size: 对齐字节数，通常是4 Bytes
 * msg_type: 存储类型，如掉电记忆数据、配置参数等
 * data_list: 数据列表
 */
#define mStoreFlash_Create(name, \
                            start_address, end_address, \
                            block_size, block_number, \
                            align_size, msg_type, \
                            data_list) \
const StoreFlashInfo_t oFlash##name##Info = { \
.u32StartAddress = (start_address), .u32EndAddress = (end_address), \
.u16BlockSize = (block_size), .u8BlockNumber = (block_number), \
.u8AlignSize = (align_size), .u8MessageType = (msg_type), }; \
const StoreData_t oFlash##name##List[] = {data_list}; \
uint8_t Flash##name##Buf[mStoreFlash_Align((STORE_MSG_HEAD_SIZE + ARRAY_SIZE(oFlash##name##List)), (align_size))]; \
const StoreFlashData_t oFlash##name##Data = { \
.pList = &(oFlash##name##List[0]), .u8Num = ARRAY_SIZE(oFlash##name##List), \
.pBuffer = Flash##name##Buf, .u8BufSize = sizeof(Flash##name##Buf), }; \
StoreFlashObject_t oFlash##name##Object = { \
.pInfo = &oFlash##name##Info, .pData = &oFlash##name##Data, }

// Store message
#define pStoreMsg(pObj)                                     ((StoreMessage_t *)((pObj)->pData->pBuffer))

// Message data
#define mStoreMsg_GetData(pObj, Idx)                        (pStoreMsg(pObj)->MsgBody[Idx])

// Data is changed
#define mStoreFlash_DataIsChanged(pObj)                     StoreData_IsChanged((pObj)->pData->pList, pStoreMsg(pObj)->MsgBody, (pObj)->pData->u8Num)

// Reload data
#define mStoreFlash_ReloadData(pObj)                        StoreData_Restore((pObj)->pData->pList, pStoreMsg(pObj)->MsgBody, pStoreMsg(pObj)->u8Length);

/** C++ } --------------------------------------------------------------------*/
#ifdef __cplusplus
}
#endif

#endif // STORE_FLASH
/******************************** End of file *********************************/
